package rullekake.beans;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import rullekake.entities.Course;
import rullekake.beans.util.JsfUtil;
import rullekake.facade.CourseFacade;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import rullekake.beans.util.LocaleHelper;
import rullekake.entities.Faculty;
import rullekake.entities.Institution;
import rullekake.entities.Outcome;
import rullekake.entities.Person;
import rullekake.entities.StudyProgram;
import rullekake.entities.Users;

@ManagedBean (name="courseController")
@SessionScoped
public class CourseController {

    private Course current;
    private DataModel items = null;
    private DataModel<Outcome> knowledgeOutcomes = null;
    private DataModel<Outcome> skillOutcomes = null;
    private DataModel<Outcome> generalOutcomes = null;
    private String searchWord;

    @EJB private rullekake.facade.CourseFacade ejbFacadeCourse;
    @EJB private rullekake.facade.UsersFacade ejbFacadeUsers;

    @ManagedProperty(value="#{outcomeController}")
    private OutcomeController outcomeController;

    public CourseController() {
    }

    public OutcomeController getOutcomeController() {
        return outcomeController;
    }

    public void setOutcomeController(OutcomeController outcomeController) {
        this.outcomeController = outcomeController;
    }
    
    public Course getSelected() {
        if (current == null) {
            current = new Course();
        }
        return current;
    }

    private CourseFacade getFacade() {
        return ejbFacadeCourse;
    }

    public DataModel getUsersCourses() {

        ListDataModel<Course> ldm =  new ListDataModel(getFacade().findAll());
        List<Course> courseList = new LinkedList<Course>();
        String loggedInAs = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
        for(Course c: ldm) {
            Collection<Person> personCollection = c.getPersonCollection();
            for (Person p: personCollection) {
                if (p.getUsers().getUsername().equals(loggedInAs)) {
                    courseList.add(c);

                }
            }
        }
        return items = new ListDataModel<Course>(courseList);
    }

    public DataModel getUsersInstitutesCourses() {
            ListDataModel<Course> ldm =  new ListDataModel(getFacade().findAll());
            List<Course> courseList = new LinkedList<Course>();
            String loggedInAs = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
            Person thisPerson = ejbFacadeUsers.findByUsername(loggedInAs).getPerson();


            // Går igjennom fagene og sjekker om de tilhørere brukerens institutt.
            for (Institution inst: thisPerson.getInstitutionCollection()){
                for (Faculty fac: inst.getFacultyCollection()) {
                    courseList.addAll(getFacade().findCoursesByFaculty(fac));
                }
            }

            return items = new ListDataModel<Course>(courseList);
    }

    public String prepareList() {
        recreateModel();
        return "List";
    }

    public String prepareView() {
        current = (Course)getItems().getRowData();
        return "course/View";
    }

    public String teacherPrepareView() {
        current = (Course)getItems().getRowData();
        return "course/View";
    }

    public String prepareCreate() {
        current = new Course();
        current.setPersonCollection(new LinkedList<Person>());
        String loggedInAs = FacesContext.getCurrentInstance().getExternalContext().getRemoteUser();
        Users user = ejbFacadeUsers.find(loggedInAs);
        System.err.println("user: " + user + ", person: " + user.getPerson() + "personCollection: " + current.getPersonCollection());
        current.getPersonCollection().add(user.getPerson());
        return "course/Create";
    }

    public String create() {
        try {
            getFacade().create(current);
            JsfUtil.addSuccessMessage("CourseCreated");
            return "mypage";
        } catch (Exception e) {
            JsfUtil.addErrorMessage("PersistenceErrorOccured");
            return null;
        }
    }

    public String prepareEdit() {
        current = (Course)getItems().getRowData();
        return "course/Edit";
    }

    public String teacherPrepareEdit() {
        current = (Course)getItems().getRowData();
        return "course/Edit";
    }

    public String createOutcome() {
        outcomeController.prepareCreate();
        outcomeController.getSelected().setCourse(current);
        return "outcome/Create";
    }

    public String editKnowledgeOutcome() {
        outcomeController.setCurrent((Outcome)knowledgeOutcomes.getRowData());
        return "outcome/Edit";
    }

    public String editSkillOutcome() {
        outcomeController.setCurrent((Outcome)skillOutcomes.getRowData());
        return "outcome/Edit";
    }

    public String editGeneralOutcome() {
        outcomeController.setCurrent((Outcome)generalOutcomes.getRowData());
        return "outcome/Edit";
    }

    public String destroyKnowledgeOutcome() {
        Outcome outcome = (Outcome)knowledgeOutcomes.getRowData();
        outcomeController.setCurrent(outcome);
        outcomeController.destroy();
        current.getOutcomeCollection().remove(outcome);
        getKnowledgeOutcomes();
        return null;
    }

    public String destroySkillOutcome() {
        Outcome outcome = (Outcome)skillOutcomes.getRowData();
        outcomeController.setCurrent(outcome);
        outcomeController.destroy();
        current.getOutcomeCollection().remove(outcome);
        getSkillOutcomes();
        return null;
    }

    public String destroyGeneralOutcome() {
        Outcome outcome = (Outcome)generalOutcomes.getRowData();
        outcomeController.setCurrent(outcome);
        outcomeController.destroy();
        current.getOutcomeCollection().remove(outcome);
        getGeneralOutcomes();
        return null;
    }

    public String update() {
        try {
            getFacade().edit(current);
            JsfUtil.addSuccessMessage("CourseUpdated");
            return "course/View";
        } catch (Exception e) {
            JsfUtil.addErrorMessage("PersistenceErrorOccured");
            return null;
        }
    }

    public String destroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage("CourseDeleted");
        } catch (Exception e) {
            JsfUtil.addErrorMessage("PersistenceErrorOccured");
        }
        current = new Course();
        recreateModel();
        return "mypage";
    }

    public DataModel getItems() {
        if (items == null) {
            items = new ListDataModel(getFacade().findAll());
        }
        return items;
    }

    public DataModel<Outcome> getKnowledgeOutcomes() {
        knowledgeOutcomes = getOutcomes(Outcome.KNOWLEDGE);
        return knowledgeOutcomes;
    }
    
    public DataModel<Outcome> getSkillOutcomes() {
        skillOutcomes = getOutcomes(Outcome.SKILL);
        return skillOutcomes;
    }

    public DataModel<Outcome> getGeneralOutcomes() {
        generalOutcomes = getOutcomes(Outcome.GENERAL_COMPETENCE);
        return generalOutcomes;
    }

    private DataModel<Outcome> getOutcomes(short type) {
        List<Outcome> list = new LinkedList<Outcome>();
        for(Outcome oc : current.getOutcomeCollection()) {
            if(oc.getOutcomeType() == type) {
                list.add(oc);
            }
        }
        return new ListDataModel<Outcome>(list);
    }

    private void recreateModel() {
        items = null;
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacadeCourse.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacadeCourse.findAll(), true);
    }

    public SelectItem[] getSemesterSelectItems() {
        String filename = LocaleHelper.getBundleName();
        SelectItem[] selectItems = new SelectItem[3];
        selectItems[0] = new SelectItem('A', ResourceBundle.getBundle(filename).getString("autumn"));
        selectItems[1] = new SelectItem('S', ResourceBundle.getBundle(filename).getString("spring"));
        selectItems[2] = new SelectItem('B', ResourceBundle.getBundle(filename).getString("both"));
        return selectItems;
    }

    public String getSemesterString() {
        String filename = LocaleHelper.getBundleName();
        if(current.getSemester() == null) {
            return "";
        }
        switch(current.getSemester()) {
            case 'A': return ResourceBundle.getBundle(filename).getString("autumn");
            case 'S': return ResourceBundle.getBundle(filename).getString("spring");
            case 'B': return ResourceBundle.getBundle(filename).getString("both");
            default: return "";
        }
    }

    public SelectItem[] getCourseLanguageSelectItems() {
        String filename = LocaleHelper.getBundleName();
        SelectItem[] selectItems = new SelectItem[2];
        selectItems[0] = new SelectItem('E', ResourceBundle.getBundle(filename).getString("en"));
        selectItems[1] = new SelectItem('N', ResourceBundle.getBundle(filename).getString("no"));
        return selectItems;
    }

    public String getCourseLanguageString() {
        String filename = LocaleHelper.getBundleName();
        if(current.getCourseLanguage() == null) {
            return "";
        }
        switch(current.getCourseLanguage()) {
            case 'E': return ResourceBundle.getBundle(filename).getString("en");
            case 'N': return ResourceBundle.getBundle(filename).getString("no");
            default: return "";
        }
    }

    /**
     * Går igjennom alle Course, matcher tekststrenger.
     * Returnerer alle treff som en ListDataModel
     *
     * Det er AND mellom flere ord
     *
     * @return
     */


    public DataModel getSearchResult() {
        System.err.println("Søker");
        LinkedList<Course> temp = new LinkedList<Course>();

        if (searchWord == null || searchWord.equals("")) {
            return new ListDataModel(temp);
        }

        String[] splitString = searchWord.split(" ");

        for(Course c: getFacade().findAll()) {
           if (c.search(splitString[0])) {
               temp.add(c);
           }
         }

        if (splitString.length > 1) {
            String[] restString = new String[splitString.length-1];
            for (int i = 1; i < splitString.length; i++) {
                restString[i-1] = splitString[i].toString();
            }
            LinkedList<Course> supersearch;
            for (String s: restString){
                supersearch = new LinkedList<Course>();
                for (Course c: temp) {
                    if (c.search(s)) supersearch.add(c);
                }
                temp = supersearch;
            }

        }


        items = new ListDataModel(temp);

        return items;
    }

    public String getSearchWord() {
        return searchWord;
    }

    public void setSearchWord(String searchWord) {
        this.searchWord = searchWord;
    }

    public void setCoursesByStudyProgram(StudyProgram studyProgram) {
        if(studyProgram == null) {
            items = new ListDataModel();
        } else {
            Collection courseCollection = studyProgram.getCourseCollection();
            if(courseCollection == null) {
                items = new ListDataModel();
            } else {
                items = new ListDataModel(new LinkedList(studyProgram.getCourseCollection()));
            }
        }
    }




    @FacesConverter(forClass=Course.class)
    public static class CourseControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            CourseController controller = (CourseController)facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "courseController");
            return controller.ejbFacadeCourse.find(getKey(value));
        }

        java.lang.Integer getKey(String value) {
            java.lang.Integer key;
            key = Integer.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Integer value) {
            StringBuilder sb = new StringBuilder();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Course) {
                Course o = (Course) object;
                return getStringKey(o.getCourseId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: "+CourseController.class.getName());
            }
        }

    }
        @FacesConverter("courseConverter")
    public static class CourseControllerConverterNamed implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            CourseController controller = (CourseController)facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "courseController");
            return controller.ejbFacadeCourse.find(getKey(value));
        }

        java.lang.Integer getKey(String value) {
            java.lang.Integer key;
            key = Integer.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Integer value) {
            StringBuilder sb = new StringBuilder();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Course) {
                Course o = (Course) object;
                return getStringKey(o.getCourseId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: "+CourseController.class.getName());
            }
        }

    }

}
